
#pragma once

#include "stdafx.h"
#include <tchar.h>
#include <Windows.h>
#include "WStr.h"

namespace WCMM{

typedef enum _LOGGING_LEVEL
{
    LEVEL_INFO = 1<<0,
    LEVEL_WORNING = 1<<1,
    LEVEL_FAILED = 1<<2,
    LEVEL_ERROR = 1<<3
    
}LOGGING_LEVEL;

typedef enum _LOGGING_MODE
{
    MODE_FILE = 0,
    MODE_STDOUT
}LOGGING_MODE;

#define LEVEL_NONE      (~(LEVEL_ALL))
#define LEVEL_ALL       (LEVEL_INFO|LEVEL_WORNING|LEVEL_FAILED|LEVEL_ERROR)
#define LEVEL_MAX		LEVEL_ERROR
#define LEVEL_MIN		LEVEL_INFO

#define LoggingSetLevel					   CLogging::GetInstance().SetLogLevel
#define LoggingSetFile                     CLogging::GetInstance().SetLoggingFile

#define LoggingString                      CLogging::GetInstance().LogString
#define LoggingWarningString(_Fmt, ...)    CLogging::GetInstance().LogString(LEVEL_WORNING, (LPCTSTR)(_Fmt), ##__VA_ARGS__)
#define LoggingErrorString(_Fmt, ...)      CLogging::GetInstance().LogString(LEVEL_ERROR, (LPCTSTR)(_Fmt), ##__VA_ARGS__) 
#define LoggingInfoString(_Fmt, ...)       CLogging::GetInstance().LogString(LEVEL_INFO, (LPCTSTR)(_Fmt), ##__VA_ARGS__)
#define LoggingFailedString(_Fmt, ...)     CLogging::GetInstance().LogString(LEVEL_FAILED,(LPCTSTR) (_Fmt), ##__VA_ARGS__)

#define LoggingWarningHexDump(_buf, _len)    CLogging::GetInstance().LoggingHexDump(LEVEL_WORNING, _buf, _len)
#define LoggingErrorHexDump(_buf, _len)      CLogging::GetInstance().LoggingHexDump(LEVEL_ERROR, _buf, _len) 
#define LoggingInfoHexDump(_buf, _len)       CLogging::GetInstance().LoggingHexDump(LEVEL_INFO,  _buf, _len)
#define LoggingFailedHexDump(_buf, _len)     CLogging::GetInstance().LoggingHexDump(LEVEL_FAILED, _buf, _len)
#define LoggingHexDump                       CLogging::GetInstance().LogHexDump

class CLogging
{
private:
    CLogging(VOID);
    CLogging(IN LPCTSTR lpszLogFile);
public:
    virtual ~CLogging(VOID);
public:
	static CLogging& GetInstance();

    BOOL 
    LogString(
        IN LOGGING_LEVEL Level, 
        IN LPCTSTR lpszFmt, 
        ...
    );
    BOOL
    LogHexDump(
        IN LOGGING_LEVEL Level,
        IN PVOID Buffer, 
        IN ULONG Length
    );

	VOID
	SetEnableColor(
		IN BOOL bEnbale
	);

    BOOL
    SetLoggingFile(
        IN LPCTSTR lpszLogFile
    );
    BOOL 
    LogString(
        IN LOGGING_LEVEL Level, 
        IN LPCTSTR lpszFmt, 
        IN va_list Args 
    );

    VOID
    SetLogLevel(
        IN ULONG Level
    );

    ULONG
    GetLogIndex(
        LOGGING_LEVEL Level
    );

private:

    BOOL LogInitialize();
    VOID LogFree();

    BOOL
    CheckLevel(
        IN LOGGING_LEVEL Level
    );

	BOOL ResetConsoleColor();
	BOOL SetConsoleColorByLevel(LOGGING_LEVEL Level);
	BOOL SetConsoleColor(WORD wAttributes);
	BOOL IsShowColor();

private:
    FILE* m_LogFile;
    LOGGING_MODE m_LogMode;
    CString m_strLogFile;
    ULONG m_Level;
	BOOL m_bEnbaleColor;
	CRITICAL_SECTION m_cs;
	WORD m_Color;
};

}